xen: Allow granting of foreign access to iomem pages, and with
authorKeir Fraser <keir.fraser@citrix.com>
Tue, 20 Nov 2007 17:26:48 +0000 (17:26 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Tue, 20 Nov 2007 17:26:48 +0000 (17:26 +0000)
arbitrary cache attributes.
Signed-off-by: Kieran Mansley <kmansley@solarflare.com>
Signed-off-by: Keir Fraser <keir.fraser@eu.citrix.com>
xen/arch/ia64/xen/mm.c
xen/arch/powerpc/mm.c
xen/arch/x86/mm.c
xen/common/grant_table.c
xen/include/asm-ia64/grant_table.h
xen/include/asm-powerpc/grant_table.h
xen/include/asm-x86/grant_table.h
xen/include/public/grant_table.h

index d55ca5d89be8650d2df109bca0002f2c39a054a2..7fde4175b6e90c260ccf2287035ffeacb8ea4a7d 100644 (file)
@@ -2144,16 +2144,18 @@ dom0vp_unexpose_foreign_p2m(struct domain* dest_dom,
 // mfn: frame: machine page frame
 // flags: GNTMAP_readonly | GNTMAP_application_map | GNTMAP_contains_pte
 int
-create_grant_host_mapping(unsigned long gpaddr,
-              unsigned long mfn, unsigned int flags)
+create_grant_host_mapping(unsigned long gpaddr, unsigned long mfn, 
+                          unsigned int flags, unsigned int cache_flags)
 {
     struct domain* d = current->domain;
     struct page_info* page;
     int ret;
 
-    if (flags & (GNTMAP_device_map |
-                 GNTMAP_application_map | GNTMAP_contains_pte)) {
-        gdprintk(XENLOG_INFO, "%s: flags 0x%x\n", __func__, flags);
+    if ((flags & (GNTMAP_device_map | 
+                  GNTMAP_application_map | GNTMAP_contains_pte)) ||
+        (cache_flags)) {
+        gdprintk(XENLOG_INFO, "%s: flags 0x%x cache_flags 0x%x\n",
+                 __func__, flags, cache_flags);
         return GNTST_general_error;
     }
 
index e6dc47f625f68e4355ac18786b63e76453c6f5a4..60c878f76a2990648860b5b1e247e4c07eb09f41 100644 (file)
@@ -168,7 +168,7 @@ static int destroy_grant_va_mapping(
 }
 
 int create_grant_host_mapping(
-    unsigned long addr, unsigned long frame, unsigned int flags)
+    unsigned long addr, unsigned long frame, unsigned int flags, unsigned int cache_flags)
 {
     if (flags & GNTMAP_application_map) {
         printk("%s: GNTMAP_application_map not supported\n", __func__);
@@ -180,6 +180,11 @@ int create_grant_host_mapping(
         BUG();
         return GNTST_general_error;
     }
+    if (cache_flags) {
+        printk("%s: cache_flags not supported\n", __func__);
+        BUG();
+        return GNTST_general_error;
+    }
     return create_grant_va_mapping(addr, frame, current);
 }
 
index e713a5a9454aec89e040e4ce8ece77e53b075ecb..9a428b19a682b734086d95d2219fc33777aa2900 100644 (file)
@@ -645,11 +645,7 @@ get_page_from_l1e(
             return 0;
         }
 
-        /* No reference counting for out-of-range I/O pages. */
-        if ( !mfn_valid(mfn) )
-            return 1;
-
-        d = dom_io;
+        return 1;
     }
 
     /* Foreign mappings into guests in shadow external mode don't
@@ -667,9 +663,8 @@ get_page_from_l1e(
                 mfn, get_gpfn_from_mfn(mfn),
                 l1e_get_intpte(l1e), d->domain_id);
     }
-    else if ( (pte_flags_to_cacheattr(l1f) !=
-               ((page->count_info >> PGC_cacheattr_base) & 7)) &&
-              !is_iomem_page(mfn) )
+    else if ( pte_flags_to_cacheattr(l1f) !=
+              ((page->count_info >> PGC_cacheattr_base) & 7) )
     {
         uint32_t x, nx, y = page->count_info;
         uint32_t cacheattr = pte_flags_to_cacheattr(l1f);
@@ -848,14 +843,16 @@ get_page_from_l4e(
 
 void put_page_from_l1e(l1_pgentry_t l1e, struct domain *d)
 {
-    unsigned long    pfn  = l1e_get_pfn(l1e);
-    struct page_info *page = mfn_to_page(pfn);
-    struct domain   *e;
-    struct vcpu     *v;
+    unsigned long     pfn = l1e_get_pfn(l1e);
+    struct page_info *page;
+    struct domain    *e;
+    struct vcpu      *v;
 
-    if ( !(l1e_get_flags(l1e) & _PAGE_PRESENT) || !mfn_valid(pfn) )
+    if ( !(l1e_get_flags(l1e) & _PAGE_PRESENT) || is_iomem_page(pfn) )
         return;
 
+    page = mfn_to_page(pfn);
+
     e = page_get_owner(page);
 
     /*
@@ -2763,8 +2760,8 @@ static int destroy_grant_va_mapping(
     return replace_grant_va_mapping(addr, frame, l1e_empty(), v);
 }
 
-int create_grant_host_mapping(
-    uint64_t addr, unsigned long frame, unsigned int flags)
+int create_grant_host_mapping(uint64_t addr, unsigned long frame, 
+                              unsigned int flags, unsigned int cache_flags)
 {
     l1_pgentry_t pte = l1e_from_pfn(frame, GRANT_PTE_FLAGS);
 
@@ -2773,6 +2770,8 @@ int create_grant_host_mapping(
     if ( !(flags & GNTMAP_readonly) )
         l1e_add_flags(pte,_PAGE_RW);
 
+    l1e_add_flags(pte, cacheattr_to_pte_flags(cache_flags >> 5));
+
     if ( flags & GNTMAP_contains_pte )
         return create_grant_pte_mapping(addr, pte, current);
     return create_grant_va_mapping(addr, pte, current);
index 1bd49523c3ac0d908a9b67eef2c34e0d14947df7..5e5b353ed92d755cd7601b990819c805d244791d 100644 (file)
@@ -198,6 +198,7 @@ __gnttab_map_grant_ref(
     int            handle;
     unsigned long  frame = 0;
     int            rc = GNTST_okay;
+    unsigned int   cache_flags;
     struct active_grant_entry *act;
     struct grant_mapping *mt;
     grant_entry_t *sha;
@@ -326,36 +327,58 @@ __gnttab_map_grant_ref(
 
     frame = act->frame;
 
+    cache_flags = (sha->flags & (GTF_PAT | GTF_PWT | GTF_PCD) );
+
     spin_unlock(&rd->grant_table->lock);
 
-    if ( unlikely(!mfn_valid(frame)) ||
-         unlikely(!((op->flags & GNTMAP_readonly) ?
-                    get_page(mfn_to_page(frame), rd) :
-                    get_page_and_type(mfn_to_page(frame), rd,
-                                      PGT_writable_page))) )
+    if ( is_iomem_page(frame) )
     {
-        if ( !rd->is_dying )
-            gdprintk(XENLOG_WARNING, "Could not pin grant frame %lx\n", frame);
-        rc = GNTST_general_error;
-        goto undo_out;
+        if ( !iomem_access_permitted(rd, frame, frame) )
+        {
+            gdprintk(XENLOG_WARNING,
+                     "Iomem mapping not permitted %lx (domain %d)\n", 
+                     frame, rd->domain_id);
+            rc = GNTST_general_error;
+            goto undo_out;
+        }
+
+        rc = create_grant_host_mapping(
+            op->host_addr, frame, op->flags, cache_flags);
+        if ( rc != GNTST_okay )
+            goto undo_out;
     }
-        
-    if ( op->flags & GNTMAP_host_map )
+    else
     {
-        rc = create_grant_host_mapping(op->host_addr, frame, op->flags);
-        if ( rc != GNTST_okay )
+        if ( unlikely(!mfn_valid(frame)) ||
+             unlikely(!((op->flags & GNTMAP_readonly) ?
+                        get_page(mfn_to_page(frame), rd) :
+                        get_page_and_type(mfn_to_page(frame), rd,
+                                          PGT_writable_page))) )
         {
-            if ( !(op->flags & GNTMAP_readonly) )
-                put_page_type(mfn_to_page(frame));
-            put_page(mfn_to_page(frame));
+            if ( !rd->is_dying )
+                gdprintk(XENLOG_WARNING, "Could not pin grant frame %lx\n",
+                         frame);
+            rc = GNTST_general_error;
             goto undo_out;
         }
-
-        if ( op->flags & GNTMAP_device_map )
+        
+        if ( op->flags & GNTMAP_host_map )
         {
-            (void)get_page(mfn_to_page(frame), rd);
-            if ( !(op->flags & GNTMAP_readonly) )
-                get_page_type(mfn_to_page(frame), PGT_writable_page);
+            rc = create_grant_host_mapping(op->host_addr, frame, op->flags, 0);
+            if ( rc != GNTST_okay )
+            {
+                if ( !(op->flags & GNTMAP_readonly) )
+                    put_page_type(mfn_to_page(frame));
+                put_page(mfn_to_page(frame));
+                goto undo_out;
+            }
+
+            if ( op->flags & GNTMAP_device_map )
+            {
+                (void)get_page(mfn_to_page(frame), rd);
+                if ( !(op->flags & GNTMAP_readonly) )
+                    get_page_type(mfn_to_page(frame), PGT_writable_page);
+            }
         }
     }
 
@@ -559,10 +582,13 @@ __gnttab_unmap_common_complete(struct gnttab_unmap_common *op)
 
     if ( op->flags & GNTMAP_device_map ) 
     {
-        if ( op->flags & GNTMAP_readonly )
-            put_page(mfn_to_page(op->frame));
-        else
-            put_page_and_type(mfn_to_page(op->frame));
+        if ( !is_iomem_page(act->frame) )
+        {
+            if ( op->flags & GNTMAP_readonly )
+                put_page(mfn_to_page(op->frame));
+            else
+                put_page_and_type(mfn_to_page(op->frame));
+        }
     }
 
     if ( (op->host_addr != 0) && (op->flags & GNTMAP_host_map) )
@@ -576,10 +602,12 @@ __gnttab_unmap_common_complete(struct gnttab_unmap_common *op)
             goto unmap_out;
         }
 
-        if ( op->flags & GNTMAP_readonly )
+        if ( !is_iomem_page(op->frame) ) 
+        {
+            if ( !(op->flags & GNTMAP_readonly) )
+                put_page_type(mfn_to_page(op->frame));
             put_page(mfn_to_page(op->frame));
-        else
-            put_page_and_type(mfn_to_page(op->frame));
+        }
     }
 
     if ( (op->map->flags & (GNTMAP_device_map|GNTMAP_host_map)) == 0 )
@@ -1595,14 +1623,16 @@ gnttab_release_mappings(
             {
                 BUG_ON(!(act->pin & GNTPIN_devr_mask));
                 act->pin -= GNTPIN_devr_inc;
-                put_page(mfn_to_page(act->frame));
+                if ( !is_iomem_page(act->frame) )
+                    put_page(mfn_to_page(act->frame));
             }
 
             if ( map->flags & GNTMAP_host_map )
             {
                 BUG_ON(!(act->pin & GNTPIN_hstr_mask));
                 act->pin -= GNTPIN_hstr_inc;
-                gnttab_release_put_page(mfn_to_page(act->frame));
+                if ( !is_iomem_page(act->frame) )
+                    gnttab_release_put_page(mfn_to_page(act->frame));
             }
         }
         else
@@ -1611,14 +1641,16 @@ gnttab_release_mappings(
             {
                 BUG_ON(!(act->pin & GNTPIN_devw_mask));
                 act->pin -= GNTPIN_devw_inc;
-                put_page_and_type(mfn_to_page(act->frame));
+                if ( !is_iomem_page(act->frame) )
+                    put_page_and_type(mfn_to_page(act->frame));
             }
 
             if ( map->flags & GNTMAP_host_map )
             {
                 BUG_ON(!(act->pin & GNTPIN_hstw_mask));
                 act->pin -= GNTPIN_hstw_inc;
-                gnttab_release_put_page_and_type(mfn_to_page(act->frame));
+                if ( !is_iomem_page(act->frame) )
+                    gnttab_release_put_page_and_type(mfn_to_page(act->frame));
             }
 
             if ( (act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) == 0 )
index e5763636f14ef5d8d428e156e87e26ac7709f4c3..d8bdb837985eca28c460a917252718251d91547a 100644 (file)
@@ -8,7 +8,8 @@
 #define INITIAL_NR_GRANT_FRAMES 1
 
 // for grant map/unmap
-int create_grant_host_mapping(unsigned long gpaddr, unsigned long mfn, unsigned int flags);
+int create_grant_host_mapping(unsigned long gpaddr, unsigned long mfn, 
+                             unsigned int flags, unsigned int cache_flags);
 int replace_grant_host_mapping(unsigned long gpaddr, unsigned long mfn, unsigned long new_gpaddr, unsigned int flags);
 
 // for grant transfer
index 16b4eb0b7c0e921a8f74f382a58e2608d1bb3be1..fc9e93f80ae11637ada3894d46c190a27406c437 100644 (file)
@@ -33,8 +33,8 @@ extern long pte_enter(ulong flags, ulong ptex, ulong vsid, ulong rpn);
 extern long pte_remove(ulong flags, ulong ptex, ulong avpn,
                        ulong *hi, ulong *lo);
 
-int create_grant_host_mapping(
-    unsigned long addr, unsigned long frame, unsigned int flags);
+int create_grant_host_mapping(unsigned long addr, unsigned long frame, 
+                             unsigned int flags, unsigned int cache_flags);
 int replace_grant_host_mapping(
     unsigned long addr, unsigned long frame, unsigned long new_addr,
     unsigned int flags);
index 16890efcd1c1e79d9c0a695f567d030e4f2c19a4..262be019fb55cd7f7cbffb5c0075f98656079f21 100644 (file)
@@ -13,8 +13,8 @@
  * Caller must own caller's BIGLOCK, is responsible for flushing the TLB, and
  * must hold a reference to the page.
  */
-int create_grant_host_mapping(
-    uint64_t addr, unsigned long frame, unsigned int flags);
+int create_grant_host_mapping(uint64_t addr, unsigned long frame,
+                             unsigned int flags, unsigned int cache_flags);
 int replace_grant_host_mapping(
     uint64_t addr, unsigned long frame, uint64_t new_addr, unsigned int flags);
 
index bae0bd1a05651ab8b3916d08e34b534b4cbeadb7..ba3467a97e72869c50e2b48d7cbcaab4fae9d0c7 100644 (file)
@@ -119,6 +119,7 @@ typedef struct grant_entry grant_entry_t;
  *  GTF_readonly: Restrict @domid to read-only mappings and accesses. [GST]
  *  GTF_reading: Grant entry is currently mapped for reading by @domid. [XEN]
  *  GTF_writing: Grant entry is currently mapped for writing by @domid. [XEN]
+ *  GTF_PAT, GTF_PWT, GTF_PCD: (x86) cache attribute flags for the grant [GST]
  */
 #define _GTF_readonly       (2)
 #define GTF_readonly        (1U<<_GTF_readonly)
@@ -126,6 +127,12 @@ typedef struct grant_entry grant_entry_t;
 #define GTF_reading         (1U<<_GTF_reading)
 #define _GTF_writing        (4)
 #define GTF_writing         (1U<<_GTF_writing)
+#define _GTF_PWT            (5)
+#define GTF_PWT             (1U<<_GTF_PWT)
+#define _GTF_PCD            (6)
+#define GTF_PCD             (1U<<_GTF_PCD)
+#define _GTF_PAT            (7)
+#define GTF_PAT             (1U<<_GTF_PAT)
 
 /*
  * Subflags for GTF_accept_transfer: